package com.personal.datacompare.tree;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.personal.core.data.DataRow;
import com.personal.core.data.DataTable;
import com.personal.core.utils.CoreUtil;
import com.personal.core.utils.ReGularUtil;
import com.personal.datacompare.config.CompareDataTableConfig;

/**
 * 合并树
 * @author cuibo
 *
 */
public class CompareTreeNode extends ITreeNode<DataTable, DataRow>
{
    /**
     *
     */
    private static final long serialVersionUID = -3319522754756109571L;

    /**
     * 获取树节点比较器
     * @param config
     * @return
     */
    public static AbstractCompareTreeNodeComparator getCompareTreeNodeComparator(CompareDataTableConfig config)
    {
        AbstractCompareTreeNodeComparator result = new CompareTreeNodeComparator();
        result.setCompareDataTableConfig(config);
        return result;
    }

    /** 合并对比配置 */
    private CompareDataTableConfig tableConfig;
    /** 合并时与之匹配上的节点集合:key:所属的树 ： value:匹配的节点 */
    private Map<DataTable, CompareTreeNode> matchNodes;
    /** 单个的匹配节点 */
    private CompareTreeNode matchNode;
    /** 差异原因 */
    private String diffReason;
    /** 是否添加差异原因的操作列 */
    private boolean diffReasonOperate = true;
    /** 是否是从合并的树中插入的节点 */
    private boolean insertNode = false;
    // 下面两个属性在回溯匹配的时候用到了
    /** 是否是本次插入节点:多个DataTable对比时使用的到 */
    private boolean thisInsertNode;
    /** 是否本次已经匹配上：多个DataTable对比时使用的到 */
    private boolean thisHasMatch;

    public CompareTreeNode(DataRow source)
    {
        super(source);
    }

    public CompareTreeNode(DataRow source, CompareDataTableConfig tableConfig)
    {
        super(source);
        this.tableConfig = tableConfig;
    }

    public CompareTreeNode(DataRow source, CompareDataTableConfig tableConfig, ITree<DataTable, DataRow> root)
    {
        super(source);
        this.tableConfig = tableConfig;
        this.root = root;
    }

    /**
     * 创建指定columnName的路径
     * @param columnName
     * @param pathFlag
     * @return
     */
    public String createNodePath(String columnName, String pathFlag)
    {
        CompareTreeNode parent = this;
        List<String> paths = new ArrayList<String>();
        while (parent != null)
        {
            paths.add(CoreUtil.parseStr(parent.getSource().getItemMap().get(columnName)));
            parent = (CompareTreeNode) parent.getParent();
        }
        StringBuilder path = new StringBuilder();
        for (int i = paths.size() - 1; i >= 0; i--)
        {
            if (i == 0)
            {
                path.append(paths.get(i));
            } else
            {
                path.append(paths.get(i)).append(pathFlag);
            }
        }
        return path.toString();
    }

    public String getDiffReason()
    {
        return diffReason;
    }

    public CompareTreeNode getMatchNode()
    {
        return matchNode;
    }

    public Map<DataTable, CompareTreeNode> getMatchNodes()
    {
        if (matchNodes == null)
        {
            matchNodes = new HashMap<DataTable, CompareTreeNode>();
        }
        return matchNodes;
    }

    public CompareDataTableConfig getTableConfig()
    {
        return tableConfig;
    }

    public boolean isDiffReasonOperate()
    {
        return diffReasonOperate;
    }

    public boolean isInsertNode()
    {
        return insertNode;
    }

    public boolean isThisHasMatch()
    {
        return thisHasMatch;
    }

    public boolean isThisInsertNode()
    {
        return thisInsertNode;
    }

    @Override
    public List<CompareTreeNode> recursionGetTreeNodes()
    {
        List<? extends ITreeNode<DataTable, DataRow>> tempResult = super.recursionGetTreeNodes();
        if (tempResult == null || tempResult.isEmpty())
        {
            return null;
        }
        List<CompareTreeNode> result = new ArrayList<CompareTreeNode>();
        for (ITreeNode<DataTable, DataRow> tempNode : tempResult)
        {
            if (!(tempNode instanceof CompareTreeNode))
            {
                continue;
            }
            result.add((CompareTreeNode) tempNode);
        }
        return result;
    }

    public void setDiffReason(String diffReason)
    {
        this.diffReason = diffReason;
    }

    public void setDiffReasonOperate(boolean diffReasonOperate)
    {
        this.diffReasonOperate = diffReasonOperate;
    }

    public void setInsertNode(boolean insertNode)
    {
        this.insertNode = insertNode;
    }

    /**
     * 设置是否为插入节点
     * @param insertNode
     * @param cascChildren  级联设置子节点
     */
    public void setInsertNode(boolean insertNode, boolean cascChildren)
    {
        this.insertNode = insertNode;
        if (cascChildren && getChildren() != null && !getChildren().isEmpty())
        {
            CompareTreeNode node = null;
            for (ITreeNode<DataTable, DataRow> inode : getChildren())
            {
                if (!(inode instanceof CompareTreeNode))
                {
                    continue;
                }
                node = (CompareTreeNode) inode;
                node.setInsertNode(insertNode, cascChildren);
            }
        }
    }

    public void setMatchNode(CompareTreeNode matchNode)
    {
        this.matchNode = matchNode;
    }

    public void setMatchNodes(Map<DataTable, CompareTreeNode> matchNodes)
    {
        this.matchNodes = matchNodes;
    }

    public void setTableConfig(CompareDataTableConfig tableConfig)
    {
        this.tableConfig = tableConfig;
    }

    public void setThisHasMatch(boolean thisHasMatch)
    {
        this.thisHasMatch = thisHasMatch;
    }

    public void setThisInsertNode(boolean thisInsertNode)
    {
        this.thisInsertNode = thisInsertNode;
    }

    /**
     * 树节点比较器
     * @author cuibo
     *
     */
    private static class CompareTreeNodeComparator extends AbstractCompareTreeNodeComparator
    {
        @Override
        public int compare(CompareTreeNode o1, CompareTreeNode o2)
        {
            if (o1 == null || o2 == null)
            {
                return 0;
            }
            if (getCompareDataTableConfig() == null)
            {
                return 0;
            }
            String columnName = getCompareDataTableConfig().getLevelColumnConfig().getColumnLabel();
            if (CoreUtil.isEmpty(columnName))
            {
                return 0;
            }
            String valueOne = CoreUtil.parseStr(o1.getSource().getValue(columnName));
            String valueTwo = CoreUtil.parseStr(o2.getSource().getValue(columnName));
            if (CoreUtil.isEmpty(valueOne))
            {
                return CoreUtil.isEmpty(valueTwo) ? 0 : 1;
            } else if (CoreUtil.isEmpty(valueTwo))
            {
                return CoreUtil.isEmpty(valueOne) ? 0 : -1;
            }
            if (ReGularUtil.CHINESENUMBER.matcher(valueOne).matches()
                    && ReGularUtil.CHINESENUMBER.matcher(valueTwo).matches())
            {
                return CoreUtil.compareNumberNoPrecision(CoreUtil.chineseToNumber(valueOne),
                        CoreUtil.chineseToNumber(valueTwo));
            } else if (ReGularUtil.CHINESENUMBERANDKH.matcher(valueOne).matches()
                    && ReGularUtil.CHINESENUMBERANDKH.matcher(valueTwo).matches())
            {
                valueOne = CoreUtil.replaceAllKh(valueOne);
                valueTwo = CoreUtil.replaceAllKh(valueTwo);
                return CoreUtil.compareNumberNoPrecision(CoreUtil.chineseToNumber(valueOne),
                        CoreUtil.chineseToNumber(valueTwo));
            } else if (ReGularUtil.LEVEL_PATTERN.matcher(valueOne).matches()
                    && ReGularUtil.LEVEL_PATTERN.matcher(valueTwo).matches())
            {
                String[] arrOne = CoreUtil.split(valueOne, ".");
                String[] arrTwo = CoreUtil.split(valueTwo, ".");
                if (arrOne.length > arrTwo.length)
                {
                    return -1;
                } else if (arrOne.length < arrTwo.length)
                {
                    return 1;
                }
                for (int i = 0; i < arrOne.length; i++)
                {
                    int result = CoreUtil.compareNumberNoPrecision(arrOne[i], arrTwo[i]);
                    if (result != 0)
                    {
                        return result;
                    }
                }
                return 0;
            }
            return 0;
        }
    }
}
